/*
** buffers.c
**
** Ed, Version 1.51, Copyright (c) 1992-94 SoftCircuits
** Redistributed by permission.
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pictor.h>
#include "ed.h"

char buffer[BUFSIZ]; 	/* general purpose buffer */
int num_lines = 0;		/* number of lines in file */
int line_ndx = 0;       /* index to current position */
int file_row = 0;       /* file row - 1 */
int file_col = 0;       /* file column - 1 */
int pref_col = 0;       /* preffered column */
int top_row = 0;        /* line at top of window */
int left_col = 0;       /* column at left of window */
int update_state = UPDATE_NOUPDATE;

LINE *head = NULL;      /* first line in file */
LINE *tail = NULL;      /* last line in file */
LINE *curr_line = NULL; /* current line */
LINE *top_line = NULL;  /* line at top of window */

int tab_size = 8;       /* tab displacement */
int insert_mode = TRUE; /* insert mode */

char untitled[] = "<Untitled>";

/*
** releases all line buffers in the linked list
*/
void free_list()
{
	LINE *line,*next;

	for(line = head;line != NULL;line = next) {
		next = line->next;
		free(line);
	}

	top_row = left_col = pref_col = line_ndx = file_row = file_col = 0;
	head = tail = curr_line = top_line = NULL;
	num_lines = 0;

} /* free_list */

/*
** removes the specified line buffer from the linked
** list
*/
void remove_from_list(LINE *line)
{
	if(head == line) head = line->next;
	if(tail == line) tail = line->prev;

	if(top_line == line) top_line = line->next;

	if(line->next != NULL)
		line->next->prev = line->prev;
	if(line->prev != NULL)
		line->prev->next = line->next;

	num_lines--;

	free(line);

} /* remove_from_list */

/*
** inserts a line into the current buffer after pos
*/
void add_to_list(LINE *line,LINE *pos)
{
	if(tail == pos) tail = line;

	line->prev = pos;
	line->next = pos->next;

	pos->next = line;
	if(line->next) line->next->prev = line;

	num_lines++;

} /* add_to_list */

/*
** appends a line to the linked list
*/
void append_line(LINE *line)
{
	if(head == NULL) {
		head = line;
		line->prev = NULL;
	}
	else {
		tail->next = line;
		line->prev = tail;
	}
	line->next = NULL;
	tail = line;

	num_lines++;

} /* append_line */

/*
** prepare buffers for new file
** if there is not enough memory even for one line of text,
** this function terminates the program
** note that this should never result in loss of data since
** we were creating a new file anyway
*/
void new_file(char *fname)
{
	LINE *new;

   clrstatus();
	free_list();

	new = malloc(sizeof(LINE));
	if(new == NULL) {
		messagebox("Out of memory\nUnable to continue","Error",MB_OK,
			&msgcolors);
		vcolor(foreback(WHITE,BLACK));
		cls();
		exit(-1);
	}

	head = tail = new;
	new->prev = NULL;
	new->next = NULL;
	new->len = 0;

	/* initialize buffer state */
	curr_line = top_line = head;
	num_lines = 1;

	strcpy(filename,(fname == NULL) ? untitled : fname);
	modified = FALSE;
	update_state = UPDATE_REPAINT;
	update_cursor(TRUE);

} /* new_file */

/*
** reads the current file into memory
*/
void load_file(char *fname)
{
	FILE *stream;
	LINE *line;
	int len,had_newline = FALSE;

	/* open input file */
	stream = fopen(fname,"rt");
	if(stream == NULL) {
		new_file(fname);
		return;
	}

   xprintf(statusbar,"Loading: %s",fname);

	/* clear existing buffers */
	free_list();

	/* read file into buffers */
	while(fgets(buffer,BUFSIZ,stream)) {
		len = strlen(buffer);
		if(buffer[len - 1] == '\n')
			had_newline = TRUE;
		else
			had_newline = FALSE;
		if(had_newline)
			len--;
		line = (LINE *)malloc(sizeof(LINE) + len);
		if(line == NULL) {
			fclose(stream);
			outofmemory();
			new_file(untitled);
			return;
		}
		strncpy(line->text,buffer,len);
		line->len = len;
		append_line(line);
	}
	/* append a blank line to follow last new-line */
	if(had_newline) {
		line = (LINE *)malloc(sizeof(LINE));
		if(line == NULL) {
			fclose(stream);
			outofmemory();
			new_file(untitled);
			return;
		}
		line->len = 0;
		append_line(line);
	}
	fclose(stream);

	if(num_lines == 0) {
		new_file(fname);
		return;
	}

	/* initialize buffer state */
	curr_line = top_line = head;

	strcpy(filename,fname);
	modified = FALSE;
	update_state = UPDATE_REPAINT;
	update_cursor(TRUE);

} /* load_file */

/*
** saves the current file to disk
*/
int save_file(char *fname)
{
	FILE *stream;
	LINE *line;

	pushstatus();
	xprintf(statusbar,"Saving: %s",fname);

	/* open file for writing */
	stream = fopen(fname,"wt");
	if(stream != NULL) {
		/* write file from buffers */
		for(line = head;line != NULL;line = line->next) {
			fwrite(line->text,sizeof(char),line->len,stream);
			if(line->next != NULL)
				fputc('\n',stream);
			if(ferror(stream))
				break;
		}
	}
	popstatus();
	if(stream == NULL || ferror(stream)) {
		messagebox("Error saving file to disk","Error",MB_OK,&msgcolors);
		fclose(stream);
		return(FALSE);
	}
	fclose(stream);

	strcpy(filename,fname);
	modified = FALSE;
	show_status();

	return(TRUE);

} /* save_file */
